define([], function() {
    angular.module('app.contextmenu', [])
        .directive('contextmenu', contextMenuDirective);

    function contextMenuDirective($timeout) {
        return {
            restrict: 'A',
            scope: {
                cmCallback: '<'
            },
            link: function(scope, element, attrs) {
                // init context menu
                $timeout(function() {
                    var contextmenu = element;
                    // hide context menu
                    jQuery(document).bind('click', function() {
                        contextmenu.removeClass('open');
                    });
                    // dropdown submenu
                    contextmenu.find('.dropdown-submenu').click(function(event) {
                        var target = (event.target || event.srcElement);
                        if (target == jQuery(this).children()[0]) {
                            return false;
                        }
                    });
                    // context menu event
                    contextmenu.parent().find(attrs.contextmenu).contextmenu(function(event) {
                        var jqWindow = jQuery(window),
                            jqDropdown = contextmenu.find('>.dropdown-menu');

                        // hide other menus
                        jQuery('nav[contextmenu]').removeClass('open');
                        jQuery('.dropdown-menu').parent().removeClass('open');
                        // show context menu
                        contextmenu.css({
                            'top': event.clientY + 'px',
                            'left': event.clientX + 'px'
                        }).addClass('open');

                        // context menu left
                        if (contextmenu.position().left + jqDropdown.outerWidth() > jqWindow.width()) {
                            contextmenu.css('left', (jqWindow.width() - jqDropdown.outerWidth()) + 'px');
                        }
                        // context menu top
                        if (contextmenu.position().top + jqDropdown.outerHeight() > jqWindow.height()) {
                            contextmenu.css('top', (jqWindow.height() - jqDropdown.outerHeight()) + 'px');
                        }

                        // call callback
                        if (typeof(scope.cmCallback) === 'function') {
                            scope.cmCallback(event, contextmenu);
                        }

                        return false;
                    });

                    // dropdown menu
                    contextmenu.find('.dropdown-submenu').on('mouseenter', function() {
                        var jqWindow = jQuery(window),
                            jqMenubar = jQuery(this),
                            jqDropdown = jqMenubar.find('>.dropdown-menu');

                        // show dropdown-menu
                        jqDropdown.css('top', '')
                        jqDropdown.removeClass('dropdown-menu-right');
                        //
                        if (jqDropdown.offset().left + jqDropdown.outerWidth() > jqWindow.width()) {
                            jqDropdown.addClass('dropdown-menu-right');
                        }
                        if (jqDropdown.offset().top + jqDropdown.outerHeight() > jqWindow.height()) {
                            jqDropdown.css('top', (jqWindow.height() - jqDropdown.offset().top - jqDropdown.outerHeight()) + 'px');
                        }
                    });

                    // append to body
                    contextmenu.appendTo(document.body);
                    // destroy
                    scope.$on('$destroy', function() {
                        contextmenu.remove();
                    });
                }, 500);
            }
        };
    }
});
